//
//  TEAUtil.cpp
//  firebkball
//
//  Created by ren jian on 18/5/28.
//
//

#include "TEAUtil.h"

uint32_t* TEAUtil::encrypt (uint32_t v[], uint32_t k[]) {
    uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
    return v;
}

uint32_t* TEAUtil::decrypt (uint32_t v[], uint32_t k[]) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
    return v;
}


void TEAUtil::transform(unsigned char* buffer)
{
    char tmp;
    tmp=buffer[0];
    buffer[0]=buffer[3];
    buffer[3]=tmp;
    
    tmp=buffer[1];
    buffer[1]=buffer[2];
    buffer[2]=tmp;
    
    tmp=buffer[4];
    buffer[4]=buffer[7];
    buffer[7]=tmp;
    
    tmp=buffer[5];
    buffer[5]=buffer[6];
    buffer[6]=tmp;
}

unsigned char* TEAUtil::encrypt(unsigned char data[],long data_len,uint32_t k[],unsigned long* pSize)
{
    int group_len = 8;
    int residues = data_len % group_len; // 余数
    //printf("encrypt residues:%d\n",residues);
    long dlen=data_len-residues;
    
    // 用于储存加密的密文，第一字节为余数的大小
    long result_len = data_len + 1;
    if (residues > 0) {
        result_len += group_len - residues;
    }
    
    unsigned char *result=new unsigned char[result_len];
    *pSize=result_len;
    result[0] = *(char*)(&residues);
    
    
    
    unsigned char* plain=new unsigned char[group_len];
    
    for (int i = 0; i < dlen; i += group_len) {
        for (int j = 0; j < group_len; j++) {
            plain[j] = data[i + j];
        }
        transform(plain);
        uint32_t* v=(uint32_t*)plain;
        //printf("pnt:%08X%08X\n", v[0], v[1]);
        encrypt(v, k);
        //printf("enc:%08X%08X\n", v[0], v[1]);
        unsigned char* a=(unsigned char*)v;
        transform(a);
        for (int k = 0; k < group_len; k++) {
            result[i + k + 1] = a[k];
        }
    }
    if (residues > 0) {
        for (int j = 0; j < residues; j++) {
            plain[j] = data[dlen + j];
        }
        int padding = group_len - residues;
        for (int j = 0; j < padding; j++) {
            plain[residues + j] = 0x00;
        }
        transform(plain);
        uint32_t* v=(uint32_t*)plain;
        //printf("pnt:%08X%08X\n", v[0], v[1]);
        encrypt(v, k);
        //printf("enc:%08X%08X\n", v[0], v[1]);
        unsigned char* a=(unsigned char*)v;
        transform(a);
        for (int k = 0; k < group_len; k++) {
            result[dlen + k + 1] = a[k];
        }
    }
    delete[] plain;
    return result;
    
    
}

unsigned char* TEAUtil::decrypt(unsigned char data[],long data_len,uint32_t k[],unsigned long* pSize)
{
    int group_len = 8;
    if (data_len % group_len != 1) {
        return NULL;
    }
    
    data_len = data_len - 1;
    long dlen; // 数据的长度
    char r=data[0];
    int residues = (int)r; // 余数
    //printf("decrypt residues:%d\n",residues);
    if (residues > 0) {
        dlen = data_len - group_len;
    } else {
        dlen = data_len;
    }
    
    unsigned char *result=new unsigned char[dlen + residues];
    *pSize=dlen + residues;
    unsigned char* enc=new unsigned char[group_len];
    
    for (int i = 0; i < dlen; i += group_len) {
        for (int j = 0; j < group_len; j++) {
            enc[j] = data[i + j + 1];
        }
        transform(enc);
        uint32_t* v= (uint32_t*)enc;
        decrypt(v, k);
        //printf("dec:%08X%08X\n", v[0], v[1]);
        unsigned char* a=(unsigned char*)v;
        transform(a);
        for (int k = 0; k < group_len; k++) {
            result[i + k] = a[k];
        }
    }
    if (residues > 0) {
        for (int j = 0; j < group_len; j++) {
            enc[j] = data[dlen + j + 1];
        }
        transform(enc);
        uint32_t* v= (uint32_t*)enc;
        decrypt(v, k);
        //printf("dec:%08X%08X\n", v[0], v[1]);
        unsigned char* a=(unsigned char*)v;
        transform(a);
        for (int k = 0; k < residues; k++) {
            result[dlen + k] = a[k];
        }
    }
    delete[] enc;
    return result;
}

unsigned char* TEAUtil::convert2str(unsigned char* decryptData,unsigned long size)
{
    unsigned char *str=new unsigned char[size+1];
    memcpy(str,decryptData,size);
    str[size] = '\0';
    return str;
}